Level 0 | Level 1 | Level 2 | Level 3 | Level 4 |
Level 5 | Level 6 | Level 7 | Level 8 | Level 9 |
Level 10 | Level 11 | Level 12 | Level 13 | Level 14 |
LEVEL 5 Technos Japan River City Ransom
We could use nes2nsf and be able to do the rip and use some of the same techniques that was used in level 4. However I have
a new technique to show you and that's using an emulator debugger with a dump function - Nesten.
Open Nesten and load the rom River City Ransom and while the music is playing open the debugger. Go to view and activate the
debugger there. Set a write breakpoint for $4000 - $4009. So type in $4000 in the start location and $4009 in the end
location. Next you click memory write. After you do this the debugger snaps on the code. And then you dump ram. This is a
range of the sound registers. You do this so that you trap the right banks and then you click the Dump $8000 - $FFFF which
is the program rom section.
Also note the stack contents on the left. I write these bytes down. These are addresses, these are all the routines that you
have executed but have not returned to yet. So everything that was done before is logged so to speak. Write these locations
down and subtract -2 from everyone, also flip the bytes around. D784 = $84D5, 7481 = $8172, 5FFA = $FA5D. These are the CPU
addresses that have been executed in the sound driver. $FA5D is the entry point of the play address and is more then likely
in the NMI code. Also note where the write was executed. At $07F8 in this case which is in WRAM and not PRG as you might
expect.
The dump file was extracted to the saves folder in the Nesten folder. Go to that folder and copy/paste the dump file to the
main directory where all your tools are. Next you disassemble the file and then load the file in edit from the edit.bat and
then you're ready just about. Also load the file in a hex editor. Also load another NSF in the hex editor so that you can
get the header from it and transfer it to the dump. This is simple. I highlight 0h - 7Fh in the hex editor and copy it. Then
I go to the dump file and paste the header at the beginning of the file. So you are ready to view the disassembly and to
edit the NSF at the same time.
Before going farther I want to talk about interrupts for a moment. In the NES you have 3 interrupts and these are located in
a vectored table at $FFFA - $FFFF in every NES rom. These are what you could call pointers and do indeed point to the code
address locations for the interrupt function. They are as follows.
As it says in the NES Music Ripping Guide by Chris Covell, that the entry to the play code is usually in the NMI code and
this is almost true everytime. Sometimes you will not find the play code here. This is why it is a good idea to write down
the contents of the stack to notepad or something.
First of all look at the disassembly of River City Ransom and look to see where the music driver code is. The code is in the
$8000 region of the PRG. Next you want to look in the NMI code but first you have to look in the bank to get the location of
the NMI. Remember the NMI vectored location is $FFFA - $FFFB. Use this formula to find the NMI pointer in the NSF.
FFFA - 8000 + 80 = NSF Offset. The answer is 807Ah Offset. So you look at these 2 bytes there at that location and flip them
arround. This is your NMI location and you should look in the disassembly at that location which is $FF4F in this case.
Look at $FF4F in the disassembly. This code is rather tricky, however I'm not going to explain it much. I will show where
the code leads to.
$FF4F> 2C 0001: BIT $0100 ; test bits, A & M,N=M7,V=M6 $FF52> 10 08: BPL $FF5C ; will not branch $FF54> 50 03: BVC $FF59 ; will branch if updating audio hardware $FF56> 4C 68F1: JMP $F168 ; jump to the main NMI code. $FF59> 4C 2BF1: JMP $F12B ; go to call to play routine. updates audio hardware.
$F15A> 20 54FA: JSR $FA54 ; leads you here.
$FA5D> 20 0380: JSR $8003 ; leads you here. This is the entry to the play address here. This address is in the stack
contents when you copied it down earlier. $8003 is the play address. Put this address in the header. This is how you find
the play address from a disassembly and emulator debugger. Tracing the NMI code can be a real pain sometimes so do it more
then once if you have to because the code can lead you in tons of different address directions.
Now that you know what the address is for the play code you can get to work on the init code. We are going to do the same
thing we did in level 4. Switch the JMP's and write some code. Here is the code in the NSF bank before you change it.
$8000> 4C 2080: JMP $8020 ; $8003> 4C 4681: JMP $8146 ; $8006> 4C 00B8: JMP $B800 ; $8009> 4C 33B8: JMP $B833 ; $800C> 4C AFBA: JMP $BAAF ; $800F> 4C 8DB8: JMP $B88D ; $8012> 4C D2B8: JMP $B8D2 ; $8015> 00: BRK ;
Change the above code with the following below.
8000 : 4C 46 81 JMP $8146 ; 8003 : 48 PHA ; 8004 : A9 00 LDA #$00 ; 8006 : 8D FF 07 STA $07FF ; 8009 : 20 20 80 JSR $8020 ; 800C : 68 PLA ; 800D : 8D FF 07 STA $07FF ; 8010 : EE FF 07 INC $07FF ; 8013 : A9 0F LDA #$0F ; 8015 : 8D 15 40 STA $4015 ; Sound Enable 8018 : 4C 20 80 JMP $8020
So now the NSF plays and sounds real good. Technos Japan has a cool sounding driver. A lot of the games sound the same and
could possibly be ripped in the same way. I've seen several of them that I could have ripped easily. Now arrange the tunes.
You will notice that the first tune is silence. I have a trick for skipping those silence tunes if there is no silence tunes
anywhere in the rip. The silence tunes have to be in order at the front of the NSF in order for this code to work.
TAY INY TYA JMP $init ; this is for skipping 1 silence tune
CLC ADC #$nn ; nn is number of tunes you want to skip JMP $init
One last thing you can do. You can optimize this rip by removing a section of the NSF. Remove $C000 - $FFFF, that's 4080h -
8080h Offset in the NSF. So that leaves a 16KB rip after you remove the excess data because you don't need it. You can
arrange the tunes at the end or somewhere where there is free space.
So this wraps this level up quite nicely. Don't forget to fill out the other header information.